package com.msb.mall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.msb.common.constant.CartConstant;
import com.msb.common.constant.OrderConstant;
import com.msb.common.dto.MemberDTO;
import com.msb.common.dto.OrderSpuDTO;
import com.msb.common.dto.SeckillOrderDto;
import com.msb.common.exception.BizCodeEnume;
import com.msb.common.exception.NoStockExecption;
import com.msb.common.utils.PageUtils;
import com.msb.common.utils.Query;
import com.msb.common.utils.R;
import com.msb.mall.order.dao.OrderDao;
import com.msb.mall.order.entity.OrderEntity;
import com.msb.mall.order.entity.OrderItemEntity;
import com.msb.mall.order.feign.MemberFeignService;
import com.msb.mall.order.feign.ProductFeignService;
import com.msb.mall.order.feign.WareFeignService;
import com.msb.mall.order.interceptor.AuthInterceptor;
import com.msb.mall.order.service.OrderItemService;
import com.msb.mall.order.service.OrderService;
import com.msb.mall.order.utils.OrderMsgProduct;
import com.msb.mall.order.vo.*;
//import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private MemberFeignService memberFeignService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private OrderMsgProduct rocketProduct;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 结算页----填写收获地址等信息
     * @return
     */
    @Override
    public OrderBalanceVo balanceOrder() throws ExecutionException, InterruptedException {
        OrderBalanceVo vo = new OrderBalanceVo();
        // 获取用户信息
        MemberDTO member = (MemberDTO) AuthInterceptor.threadLocal.get();

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            // 1.远程调用member服务，获取用户收货地址；
            R r = memberFeignService.getMemberAddress(member.getId());
            String json = JSON.toJSONString(r.get("addressList"));
            List<MemberAddressVo> memberAddressVo = JSON.parseObject(json, new TypeReference<List<MemberAddressVo>>(){});
            vo.setAddress(memberAddressVo);
        }, executor);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            // 2.查询购物车中选中的商品信息
            List<OrderItemVo> items = getOpetionsByMemberNickName(member);
            vo.setItems(items);
        }, executor);
        // 3.计算订单总金额，和优惠后需要支付的金额---OrderBalanceVo中方法自动计算
        // 4.防重提交token存储
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        redisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PERFIX+member.getId(),token);
        vo.setOrderToken(token);
        CompletableFuture.allOf(future1,future2).get();
        return vo;
    }


    /**
     *  已填写收货地址-提交商品
     * @param vo
     */
//    @GlobalTransactional
    @Transactional
    @Override
    public R orderSubmit(OrderSubmitVo vo) {
        MemberDTO member = (MemberDTO) AuthInterceptor.threadLocal.get();
        OrderEntity order = null;
        // 1.验证是否重复提交  保证Redis中的token 的查询和删除是一个原子性操作
        // 也可使用  private Lock lock = new ReentrantLock(); lock.lock() 加锁的方式， lock.unlock();
        String key = OrderConstant.ORDER_TOKEN_PERFIX + member.getId();
        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class)
                , Arrays.asList(key)
                , vo.getOrderToken());
        if(result == 0){
            // 表示验证失败 说明是重复提交
            return R.error(BizCodeEnume.ORDER_CREATE_EXCEPTION.getCode(), BizCodeEnume.ORDER_CREATE_EXCEPTION.getMsg());
        }
        // 防重提交验证
/*        String redisOrderToken = redisTemplate.opsForValue().get(key);
        String orderToken = vo.getOrderToken();
        if (orderToken.equals(redisOrderToken)){*/
        // 第一次提交，生成订单 oms_order
        order = createOrder(vo, member);
        this.save(order);

        // 获取选中的商品
        List<Long> skuIds = vo.getSkuIds();
        List<OrderItemVo> checkCartItems = getOpetionsByMemberNickName(member);

        // 生成订单项 oms_order_item
        List<OrderItemEntity> orderItem = createOrderItem(checkCartItems,skuIds, member, order);
        orderItemService.saveBatch(orderItem);

        // 锁定库存
        R r = wareFeignService.toLockStock(checkCartItems);
        if (r.getCode() != 0){
            throw new NoStockExecption(10000l);
        }
        // 会员积分增长
//      int i=1/0;

        // rocketmq发送消息
        rocketProduct.sendMsg(order.getOrderSn());

/*            redisTemplate.opsForHash().delete(CartConstant.CART_PERFIX + member.getNickname(),JSON.toJSONString(vo.getSkuIds()));
        }else {
             重复提交
            return R.error(BizCodeEnume.ORDER_CREATE_EXCEPTION.getCode(), BizCodeEnume.ORDER_CREATE_EXCEPTION.getMsg());
        }*/

        return R.ok().put("order",order);
    }

    /**
     * 根据订单编号获取订单信息
     * @param orderSN
     * @return
     */
    @Override
    public PayVo getOrderByOrderSn(String orderSN) {
        return baseMapper.getOrderByOrderSn(orderSN);
    }

    /**
     * 修改订单状态
     * @param orderSN
     * @param code
     */
    @Override
    public void updateOrderStatus(String orderSN, int code) {
        // 更新订单状态
        baseMapper.updateStatusByOrderSN(orderSN,code);
        // 减掉锁定库存

        // 会员积分增加
    }

    /**
     * 秒杀订单
     * @param seckillOrderDto
     */
    @Override
    public void createSeckillOrder(SeckillOrderDto seckillOrderDto) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(seckillOrderDto.getMemberId());
        orderEntity.setOrderSn(seckillOrderDto.getOrderSN());
        orderEntity.setMemberUsername(seckillOrderDto.getMemberName());
        orderEntity.setPayAmount(seckillOrderDto.getSeckillPrice());
        orderEntity.setStatus(OrderConstant.OrderStatusEnum.FOR_THE_PAYMENT.getCode());
        this.save(orderEntity);

        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(seckillOrderDto.getOrderSN());
        orderItemEntity.setOrderId(orderEntity.getId());
        // spu sku
//        R spuInfoBySkuId = productFeignService.getSpuInfoBySkuId(seckillOrderDto.getSkuId());
        orderItemService.save(orderItemEntity);
    }

    /**
     * 获取当前用户的购物车商品信息
     * @param member
     * @return
     */
    private List<OrderItemVo> getOpetionsByMemberNickName(MemberDTO member) {
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(CartConstant.CART_PERFIX + member.getNickname());
        List<OrderItemVo> checkCartItems = new ArrayList<>();
        Set<Object> keys = ops.keys();
        for (Object key : keys) {
            Object o = ops.get((String) key);
            OrderItemVo checkItem = JSON.parseObject((String) o, OrderItemVo.class);
            if (checkItem.isCheck()){
                checkCartItems.add(checkItem);
            }
        }
        return checkCartItems;
    }

    /**
     * 生成订单明细。
     *
     * @param checkCartItems
     * @param skuIds
     * @param member
     * @param order
     * @return
     */
    private List<OrderItemEntity> createOrderItem(List<OrderItemVo> checkCartItems, List<Long> skuIds, MemberDTO member, OrderEntity order) {
        ArrayList<OrderItemEntity> orderItemEntities = new ArrayList<>();

        // 获取每个商品对应的spu信息
        R r = productFeignService.getSpuInfoBySkuIds(skuIds);
        HashMap<Long, OrderSpuDTO> spuMap = null;
        if (null != r.get("map")){
            String map = JSON.toJSONString(r.get("map"));
            spuMap = JSON.parseObject(map, new TypeReference<HashMap<Long, OrderSpuDTO>>() {});
        }
        for (OrderItemVo checkCartItem : checkCartItems) {
            // 添加sku信息
            OrderItemEntity orderItemEntity = new OrderItemEntity();
            orderItemEntity.setOrderId(order.getId());
            orderItemEntity.setOrderSn(order.getOrderSn());
            orderItemEntity.setSkuId(checkCartItem.getSkuId());
            orderItemEntity.setSkuName(checkCartItem.getTitle());
            orderItemEntity.setSkuPic(checkCartItem.getImage());
            orderItemEntity.setSkuPrice(checkCartItem.getPrice());
            orderItemEntity.setSkuQuantity(checkCartItem.getCount());
            String attrStr = StringUtils.collectionToDelimitedString(checkCartItem.getSkuAttr(), ",");
            orderItemEntity.setSkuAttrsVals(attrStr);
            orderItemEntity.setGiftGrowth(checkCartItem.getPrice().intValue());
            orderItemEntity.setGiftIntegration(checkCartItem.getPrice().intValue());
            // 添加spu信息
            OrderSpuDTO orderSpuDTO = spuMap.get(checkCartItem.getSkuId());
            orderItemEntity.setSpuId(orderSpuDTO.getSpuId());
            orderItemEntity.setSpuName(orderSpuDTO.getSpuName());
            orderItemEntity.setSpuBrand(orderSpuDTO.getSpuBrand());
            orderItemEntity.setSpuPic(orderSpuDTO.getSpuPic());
            orderItemEntity.setCategoryId(orderSpuDTO.getCategoryId());
            orderItemEntities.add(orderItemEntity);
        }
        return orderItemEntities;
    }

    /**
     * 生成订单
     * @param vo
     * @param member
     * @return
     */
    private OrderEntity createOrder(OrderSubmitVo vo, MemberDTO member) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(member.getId());
        // 订单号
        String orderSn = IdWorker.getTimeId();
        orderEntity.setOrderSn(orderSn);
        orderEntity.setMemberUsername(member.getUsername());
        orderEntity.setTotalAmount(vo.getPrice());
        orderEntity.setPayAmount(vo.getPayPrice());
        orderEntity.setStatus(OrderConstant.OrderStatusEnum.FOR_THE_PAYMENT.getCode());
        // 根据收获地址ID获取收获地址的详细信息
        R r = memberFeignService.info(vo.getAddrId());
        if (null != r.get("memberReceiveAddress")){
            MemberAddressVo memberAddressVo = JSON.parseObject(JSON.toJSONString(r.get("memberReceiveAddress")), MemberAddressVo.class);
            orderEntity.setReceiverCity(memberAddressVo.getCity());
            orderEntity.setReceiverDetailAddress(memberAddressVo.getDetailAddress());
            orderEntity.setReceiverName(memberAddressVo.getName());
            orderEntity.setReceiverPhone(memberAddressVo.getPhone());
            orderEntity.setReceiverPostCode(memberAddressVo.getPostCode());
            orderEntity.setReceiverRegion(memberAddressVo.getRegion());
            orderEntity.setReceiverProvince(memberAddressVo.getProvince());
        }
        return orderEntity;
    }

}